package com.realife.eson.common.util.information;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.github.wnameless.json.flattener.JsonFlattener;
import com.realife.eson.common.asserts.AssertNP;
import com.realife.eson.common.result.R;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @version V1.0
 * @author: guangcheng
 * @date: 2022/5/28 16:44
 * @description:
 */
@Slf4j
public class MeJSONUtil {

    public static Logger logger = LoggerFactory.getLogger(MeJSONUtil.class);
    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        mapper.setDateFormat(sdf);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }


    private MeJSONUtil() {
    }


    public static synchronized List<String> getJsonAllKeys0(JSONObject object) {
        jsonObjectAllKeys.clear();
        List<String> keys = jsonAllKey(object);
        return new ArrayList<>(keys);
    }

    /**
     *
     */
    private static List<String> jsonObjectAllKeys = new ArrayList<>();

    /**
     * @param jsonObject
     * @return
     */
    private static List<String> jsonAllKey(JSONObject jsonObject) {
        Set<String> keySet = jsonObject.keySet();
        if (AssertNP.legalParams(keySet)) {
            for (String key : keySet) {
                jsonObjectAllKeys.add(key);
                Object o = jsonObject.get(key);
                if (AssertNP.legalParams(o)) {
                    if (o instanceof JSONArray) {
                        JSONArray arr1 = JSONObject.parseObject(JSON.toJSONString(o), JSONArray.class);
                        if (AssertNP.legalParams(arr1)) {
                            for (Object o1 : arr1) {
                                if (o1 instanceof JSONObject || o1 instanceof JSONArray) {
                                    jsonAllKey(getJSONObject(o1));
                                }
                            }
                        }
                    } else if (o instanceof JSONObject) {
                        jsonAllKey(getJSONObject(o));
                    }
                }

            }
        }
        return jsonObjectAllKeys;
    }


    public static JSONObject getJSONObject(Object object) {
        return JSON.parseObject(JSON.toJSONString(object), JSONObject.class);
    }


    public static JSONObject getJSONObject1(String json) {
        return JSON.parseObject(json, JSONObject.class);
    }


    /**
     * //return JSONObject.parseObject(json, JSONObject.class);
     *
     * @param json
     * @return
     */
    public static JSONObject getJSONObject(String json) {
        return JSON.parseObject(json, new com.alibaba.fastjson.TypeReference<JSONObject>() {
        });
    }


    public static <T> T getT(Object source, com.alibaba.fastjson.TypeReference<T> typeReference) {
        String jsonString = getJSONString(source);
        return JSON.parseObject(jsonString, typeReference);
    }


    public static <T> T getT(String json, com.alibaba.fastjson.TypeReference<T> typeReference) {
        return JSON.parseObject(json, typeReference);
    }


    public static <T> List<T> jsonArr2JavaList(JSONArray jsonArray, Class<T> cls) {
        return jsonArray.toJavaList(cls);
    }


    /**
     *
     * @param json
     * @param key
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T getT(String json, String key, com.alibaba.fastjson.TypeReference<T> typeReference) {
        JSONObject jsonObject = getJSONObject(json);
        Object object = jsonObject.get(key);
        return JSON.parseObject(getJSONString(object), typeReference);
    }


    /**
     * return JSONObject.parseObject(JSON.toJSONString(object), JSONArray.class);
     *
     * @param object
     * @return
     */
    public static JSONArray getJSONArray(Object object) {
        return JSON.parseArray(getJSONString(object));
    }


    public static JSONArray getJSONArray(String json) {
        return JSON.parseArray(json);
    }


    public static String getJSONString(Object object) {
        return JSON.toJSONString(object);
    }


    public static <T> List<T> parseArray(String jsonArr, Class<T> tClass) {
        return JSON.parseArray(jsonArr, tClass);
    }


    /**
     * @param jsonObject
     * @param keyArr     [k1,k2,...,kn]
     * @return
     */
    public static Object getAnyValueFromJson(JSONObject jsonObject, String[] keyArr) {
        JSONObject jsonObj = null;
        if (AssertNP.legalParams(jsonObject, keyArr)) {
            jsonObj = jsonObject;
            for (int i = 0; i < keyArr.length; i++) {
                Object result = getObjectByKey(jsonObj, keyArr[i]);
                if (result instanceof JSONObject) {
                    jsonObj = getJSONObject(result);
                } else {
                    return result;
                }
            }
        }
        return jsonObj;
    }


    public static Object getObjectByKey(JSONObject jsonObject, String key) {
        JSONObject jsonObj = null;
        Object o = jsonObject.get(key);
        if (o instanceof JSONObject) {
            jsonObj = getJSONObject(o);
        } else {
            return o;
        }
        return jsonObj;
    }


    /**
     * @param object
     * @return
     */
    public static List<JSONObject> getObjListFromJsonArrObj(Object object) {
        List<JSONObject> jsonObjects = new ArrayList<>();
        if (AssertNP.legalParams(object)) {
            if (object instanceof JSONArray) {
                JSONArray jsonArray = getJSONArray(object);
                for (Object obj : jsonArray) {
                    if (obj instanceof JSONObject) {
                        jsonObjects.add(getJSONObject(obj));
                    }
                }
            }
        }
        return jsonObjects;
    }



    private static StringBuilder builder = new StringBuilder();

    /**
     * 找出包含key的父节点
     * <content>|<content>plugins|<content>envConfig|<content>defVar|<content>configFile|<content>secret|
     *
     * @param jsonObject
     * @param jsonAllKeys0
     * @param key
     * @param guide
     * @return
     */
    public static String getTraceOfKey(JSONObject jsonObject, List<String> jsonAllKeys0, String key, String guide) {
        if (AssertNP.legalParams(jsonAllKeys0)) {
            if (jsonAllKeys0.contains(key)) {
                builder.append(guide + "|");
            }
            for (String key0 : jsonAllKeys0) {
                if (AssertNP.legalParams(jsonObject)) {
                    Object obj = getObjectByKey(jsonObject, key0);
                    if (AssertNP.legalParams(obj) && obj instanceof JSONObject) {
                        JSONObject jsonObject1 = getJSONObject(obj);
                        List<String> jsonAllKeys01 = getJsonAllKeys0(jsonObject1);
                        getTraceOfKey(jsonObject1, jsonAllKeys01, key, key0);
                    }
                }
            }
        }
        return builder.toString();
    }


    /**
     * 根据json路径返回JSONObject
     *
     * @param json
     * @param path
     * @return
     */
    public static JSONObject jsonPathToJSONObject(String json, String path) {
        JsonNode jsonNode = getJsonNode(json);
        if (AssertNP.legalParams(jsonNode)) {
            JsonNode node = jsonNode.at(path);
            return anyTypeFromJsonNode(node, new TypeReference<JSONObject>() {
            });
        }
        return null;
    }


    /**
     * 获取JsonNode
     *
     * @param json
     * @return
     */
    public static JsonNode getJsonNode(String json) {
        JsonNode node = null;
        try {
            node = mapper.readTree(json);
        } catch (JsonProcessingException e) {
            logger.error("json转树失败,jsonStr:{}", json);
        }
        return node;
    }


    /**
     * @param node
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T anyTypeFromJsonNode(JsonNode node, TypeReference<T> typeReference) {
        T t = null;
        try {
            if (node instanceof MissingNode) {
                return null;
            }
            String targetStr = node.toString();
            t = mapper.readValue(targetStr, typeReference);
        } catch (JsonProcessingException e) {

        }
        return t;
    }


    /**
     * @param json
     * @param path          path 路径,/为根节点,例/aaa/bbb
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T searchJsonByPath(String json, String path, TypeReference<T> typeReference) {
        JsonNode node = null;
        T t = null;
        try {
            node = mapper.readTree(json);
            JsonNode targetNode = node.at(path);
            if (targetNode instanceof MissingNode) {
                logger.error("searchJsonByPath目标路径不存在,json:{},path:{}", json, path);
            } else {
                String targetStr = targetNode.toString();
                t = mapper.readValue(targetStr, typeReference);
            }
        } catch (Exception e) {
            logger.error("json转树失败,jsonStr:{}", json);
        }
        return t;
    }



    /**
     * 扁平化json
     *
     * @param jsonStr
     * @return
     */
    public static Map<String, Object> flattenAsMap(String jsonStr) {
        return JsonFlattener.flattenAsMap(jsonStr);
    }



    public static void main(String[] args) {

        String jsonStr = "{\"hello\": \"world\"}";
        JSONObject jsonObject = R.getTargetObj(jsonStr, new com.alibaba.fastjson.TypeReference<JSONObject>() {
        });

        JSONObject jsonObject1 = getJSONObject(jsonStr);
        System.out.println("jsonObject1 =\n" + jsonObject1);
        String jsonString = getJSONString(jsonObject1);
        System.out.println("jsonString =\n" + jsonString);
        System.out.println("jsonObject1.toJSONString() = " + jsonObject1.toJSONString());
        System.out.println("jsonObject1.toString() = " + jsonObject1.toString());


        JSONObject jsonObject2 = getJSONObject(jsonObject1);
        System.out.println("jsonObject2 =\n" + jsonObject2);
        JSONObject jsonObject3 = getJSONObject(getJSONString(jsonObject1));
        System.out.println("jsonObject3 =\n" + jsonObject3);


        Map<String, Object> map = JsonFlattener.flattenAsMap(jsonStr);
        System.out.println("map =\n" + map);


        /**
         * 格外注意这种对象
         *
         */
        Object msg = "{\"hello\": \"world\"}";
        JSONObject result = R.getTargetObj(msg.toString(), new com.alibaba.fastjson.TypeReference<JSONObject>() {
        });
        System.out.println("result =\n" + result);// {"hello":"world"}  可以
        String jsonString1 = getJSONString(msg);
        System.out.println("jsonString1 =\n" + jsonString1); // "{\"hello\": \"world\"}"  不行

        System.out.println("msg.toString() = " + msg.toString());// {"hello": "world"} 可以



    }


}

